package ssx.demo.redisson_redlock_demo.service;

import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import org.redisson.RedissonRedLock;
import org.redisson.api.*;
import org.redisson.client.RedisClient;
import org.redisson.client.RedisClientConfig;
import org.redisson.client.RedisConnection;
import org.redisson.client.protocol.CommandsData;
import org.redisson.client.protocol.RedisCommands;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisKeyValueTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Service("myServiceRedis")
public class ServiceRedis {

    private final Logger logger= LoggerFactory.getLogger(this.getClass());

    @Autowired
    @Qualifier("myRedissonClient")
    RedissonClient redissonClient;

    /**
     * 实现redlock具体逻辑
     */
    public void fun(){
        logger.info("开启线程："+Thread.currentThread().getName());

        //因为我自己的redis cluster集群配置3台，所以根据redlock算法我定义3个lock就行了，再多定义就没有意义了。虽然可以定义多个，最少定义1个
        //并且注意三个锁名字不可重复。

        //我有一个不确定问题：看官网说redis集群cluster分片原理（把数据存到哪台节点的算法）是：通过hash算法进行分区的，类似于oracle区分表之hash分区表
        //所以我指定了3个key不一样的lock，通过hash分区会 各个节点存一个lock吧，至少我demo里面观察的是这样的
        RLock lock1 = redissonClient.getLock("my_redlock_0001");
        RLock lock2 = redissonClient.getLock("my_redlock_0002");
        RLock lock3 = redissonClient.getLock("my_redlock_0003");
        RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);
        try {
            //上面定义3个锁，并且每个节点持有一把锁，接下来开始上锁了
            //下面的方法是当前线程开始抢锁，没有超时时间，一直抢 ·直到抢到为止。如果抢到了，设置10秒之后自动释放锁，这是为了避免死锁
            redLock.lock(10,TimeUnit.SECONDS);
            //上面的lock()方法会一直独占阻塞当前线程 直到抢到锁为止，当然也有异步抢锁方法： RFuture<Void> lockAsync = redLock.lockAsync();
            logger.info("获取锁成功"+Thread.currentThread().getName());
            //TODO
            //在这执行抢到锁之后的逻辑，我这里是获取唯一
            Thread.sleep(1000);
            /**
             * 发现redis有个命令支持Redis Incr 命令
             * 每次执行这个命令都会进行+1操作，并且这个是原子操作 多线程安全的
             * 如果多线程并发获取唯一id的需求 可以不用加锁 直接调用redis这个incr命令就行
             * 但是不支持多线程修改此key值 例如每天置零 这个就需要锁的控制了
             */

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            //无论如何都要释放锁
            redLock.unlock();
        }
    }


    /**
     * redis curd
     */
    @Autowired
    private RedisTemplate<String,  String> redisTemplate;

    public void curd(){
        System.out.println(1);
        ValueOperations<String, String> ops = redisTemplate.opsForValue();
        //设置值 如果没有就新建 有的话会覆盖
        ops.set("test_1","test_1value2");

        Long myincr_1 = ops.increment("myincr_1");

        //获取值
        String test_1 = ops.get("test_12");

        redisTemplate.delete("test_1");

        System.out.println(1);

    }

}
